package org.xx.armory.service;

import org.xx.armory.db.SessionFactory;
import org.xx.armory.db.TransactionManager;

import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;

import static java.lang.Runtime.getRuntime;
import static java.lang.String.valueOf;
import static java.lang.System.getProperty;
import static java.net.InetAddress.getLocalHost;
import static org.apache.commons.lang3.StringUtils.join;
import static org.apache.commons.lang3.time.DateFormatUtils.format;

/**
 * 用于提供服务器系统信息的服务。
 *
 * @author Haart
 */
public final class SystemService
        extends AbstractService {

    /**
     * 获取当前的工作线程状态集合。
     *
     * @param ctx
     *         服务上下文。
     * @return 当前的工作线程状态集合。
     */
    public Map<String, String> threads(
            ServiceContext ctx
    ) {
        final Map<String, String> ret = new LinkedHashMap<>();
        final Collection<Thread> threads = new TreeSet<>(Comparator.comparing(Thread::getId));
        final long currentThreadId = Thread.currentThread().getId();
        for (final Thread t : Thread.getAllStackTraces().keySet()) {
            if (t != null && t.getId() != currentThreadId) {
                threads.add(t);
            }
        }

        for (final Thread t : threads) {
            final StackTraceElement[] stackTrace = t.getStackTrace();
            final String key = "[" + t.getId() + "] " + t.getName();
            final String value;
            if (stackTrace != null) {
                value = t.getState() + "\n\n" + join(stackTrace, '\n');
            } else {
                value = t.getState().toString();
            }
            ret.put(key, value);
        }
        return ret;
    }

    /**
     * 获取服务器系统信息。
     *
     * @param ctx
     *         服务上下文。
     * @return 服务器系统信息。
     */
    public final Map<String, String> info(
            ServiceContext ctx
    ) {
        final Map<String, String> ret = new TreeMap<>();

        // 输出环境变量信息。
        ret.put("java.version", getProperty("java.version"));
        ret.put("armory.version", "2.1");
        ret.put("user.dir", getProperty("user.dir"));
        ret.put("user.name", getProperty("user.name"));
        ret.put("user.language", getProperty("user.language"));
        final String osName = getProperty("os.name") + " " + getProperty("os.version");
        final String osArch = getProperty("os.arch");
        if (!osArch.isEmpty()) {
            ret.put("os", osName + "(" + osArch + ")");
        } else {
            ret.put("os", osName);
        }

        // 输出服务器的硬件信息
        ret.put("available-processors", valueOf(getRuntime().availableProcessors()));
        ret.put("max-memory", String.format("%.2f MB", getRuntime().maxMemory() / (1024D * 1024D)));
        ret.put("free-memory", String.format("%.2f MB", getRuntime().freeMemory() / (1024D * 1024D)));

        // 输出服务上下文呢的信息。
        ret.put("context", ctx.toString());

        // 输出服务器日期时间信息。
        final Calendar now = Calendar.getInstance();
        ret.put("datetime", format(now, "yyyy-MM-dd HH:mm:ss"));
        ret.put("timezone", now.getTimeZone().getDisplayName());

        // 输出服务器IP地址信息。
        try {
            ret.put("ip", valueOf(getLocalHost()));
        } catch (UnknownHostException ex) {
            ret.put("ip", "<unknown>");
        }

        // 输出数据源信息。
        final SessionFactory sessionFactory = getSessionFactory();
        if (sessionFactory != null) {
            final TransactionManager transactionManager = sessionFactory.getTransactionManager();
            if (transactionManager != null) {
                ret.put("data-source", valueOf(transactionManager.getDataSource()));
                ret.put("transaction-manager", valueOf(transactionManager));
            }
            ret.put("session-factory", valueOf(sessionFactory));
        }

        return ret;
    }

    /**
     * 抛出运行时错误。
     *
     * @param ctx
     *         服务上下文。
     */
    public final void exception(
            ServiceContext ctx
    ) {
        throw new RuntimeException("an exception thrown!");
    }
}
